use strict;
use DBI;
use DBD::ODBC;
use POSIX;
use Time::HiRes qw(time);

my $flagLowDim = 0;
my $iter = 0;

#require 'ConvertUsingDummyVariables.pl';
require 'FilterData.pl';

open (KEYINFO, '> NTDB_Keys.txt');
open (LOG, '> NTDB_Log.txt');
open (OUTHD, '> NTDB_HD.txt');
open (OUTLD, '> NTDB_LD.txt');
open (EDSYSBP, '> normalizedEDSYSBP.txt');
open (EDRESPRATE, '> normalizedEDRESPRATE.txt');

# Set connection parameters
my $dsn = 'dbi:ODBC:NTDBDriver';
my ($username, $password) = ('trauma', 'trauma');
print LOG "username = $username, password = $password\n";
# Connect to the database
my $ntdb = DBI -> connect($dsn  ,$username,$password);

# Writing, printing, preparing and executing sql query
my $sql = "EXEC sp_NTDB_ExtractRelevantCols";
print LOG "SQL COMMAND EXECUTED: $sql\n";
my $sth = $ntdb -> prepare($sql);
$sth -> execute();

# Declare hashes
my (%hAISCODE, %hAISSCORE, %hBODYREGION, %hINC_KEY, %hAGE, %hGENDER, %hDCODE, %hLOS, %hECODE, %hECODE_ROW, %hECODE_COL, %hEDSYSBP, %hEDRESPRATE, %hEDGCSEYE, %hEDGCSVERB, %hEDGCSMOTOR, %hEDGCSTOTAL, %hINJURYTYPE, %hINJURYSITE, %hOUTPUT);
my (%hINC_KEY_AISCODE, %hINC_KEY_AISSCORE, %hINC_KEY_BODYREGION, %hINC_KEY_DCODE, %hINC_KEY_ECODE, %hINC_KEY_ECODE_ROW, %hINC_KEY_ECODE_COL, %hINC_KEY_EDGCSEYE, %hINC_KEY_EDGCSVERB, %hINC_KEY_EDGCSMOTOR, %hINC_KEY_EDGCSTOTAL, %hINC_KEY_INJURYTYPE, %hINC_KEY_INJURYSITE, %hDCODE_DCODE, %hDCODE_INJURYTYPE, %hAISCODE_AISCODE, %hAISCODE_INJURYTYPE, %hAISSCORE_BODYREGION);

# Declare corresponding hash keys
my ($INC_KEY, $AISCODE, $AISSCORE, $BODYREGION, $AGE, $GENDER, $DCODE, $LOS, $DISCHDISP, $DISSTATUS, $ECODE, $EDSYSBP, $EDRESPRATE, $EDGCSEYE, $EDGCSVERB, $EDGCSMOTOR, $EDGCSTOTAL, $EDDISP, $INJURYTYPE, $INJURYSITE);

# Setting subroutine for converting to dummy variables

my ($EDGCSEYE_DUMMY, $EDGCSVERB_DUMMY, $EDGCSMOTOR_DUMMY, $EDGCSTOTAL_DUMMY);
my $OUTPUT;

my $startTime = time();
while(($INC_KEY, $AISCODE, $AISSCORE, $BODYREGION, $AGE, $GENDER, $DCODE, $LOS, $DISCHDISP, $DISSTATUS, $ECODE, $EDSYSBP, $EDRESPRATE, $EDGCSEYE, $EDGCSVERB, $EDGCSMOTOR, $EDGCSTOTAL, $EDDISP, $INJURYTYPE, $INJURYSITE) = $sth -> fetchrow_array())
{
    $iter++;
    $INC_KEY = trim($INC_KEY); $AISCODE = trim($AISCODE); $AISSCORE = trim($AISSCORE); $BODYREGION = trim($BODYREGION);
    $AGE = trim($AGE); $GENDER = trim($GENDER); 
    $DCODE = trim($DCODE);
    
    #if($INC_KEY == 962703)
    #{
    #    print $INC_KEY;
    #}
    # Add 1 to LOS to handle patients with LOS = 0 (Dead on arrival).
    # Since, the survival function S(t=0) = 1. Therefore, theoretically,
    # a person cannot be dead when the study was started.
    $LOS = trim($LOS) + 1;
    
    $DISCHDISP = trimIfEmpty($DISCHDISP); $DISSTATUS = trimIfEmpty($DISSTATUS);
    $ECODE = trim($ECODE);
    $EDSYSBP = trim($EDSYSBP); $EDRESPRATE = trim($EDRESPRATE); $EDGCSEYE = trimIfEmpty($EDGCSEYE); $EDGCSVERB = trimIfEmpty($EDGCSVERB); $EDGCSMOTOR = trimIfEmpty($EDGCSMOTOR); $EDGCSTOTAL = trimIfEmpty($EDGCSTOTAL); $EDDISP = trimIfEmpty($EDDISP);
    $INJURYTYPE = trim($INJURYTYPE); $INJURYSITE = trim($INJURYSITE);
    
    # If AISSCORE is NULL then replace it with the post-dot digit of aiscode
    if($AISSCORE eq "null" or $AISSCORE eq "NULL")
    {
        $AISSCORE = floor(10*($AISCODE-floor($AISCODE)));
    }
    
    # Remove "unknown" AISSCORE values (corresponding to AISSCORE = 9)
    if($AISSCORE == 9)
    {
        $AISSCORE = "REMOVEPATIENT";
    }
        
    # Extract the pre-dot number from AISCODE
    $AISCODE = floor($AISCODE);
    
    # ICD9 Filtering
    $DCODE = filterICD9($DCODE);
    
    # EDGCS Filtering
    ($EDGCSEYE, $EDGCSVERB, $EDGCSMOTOR, $EDGCSTOTAL) = filterGCS($EDGCSEYE, $EDGCSVERB, $EDGCSMOTOR, $EDGCSTOTAL);
    
    #$EDGCSEYE = 1;
    #$EDGCSVERB = 1;
    #$EDGCSMOTOR = 1;
    #$EDGCSTOTAL = 4;

    # ECODE Filtering
    my ($ECODE_ROW, $ECODE_COL);
    ($ECODE,$ECODE_ROW,$ECODE_COL) = filterECODE($ECODE);

    # EDSYSBP Normalization and Fitting
    $EDSYSBP = normalizeEDSYSBP($EDSYSBP,$AGE);
    
    # EDRESPRATE Normalization and Fitting
    $EDRESPRATE = normalizeEDRESPRATE($EDRESPRATE,$AGE);
    
    
    # Output Filtering
    $OUTPUT = filterStatus($DISCHDISP, $DISSTATUS, $EDDISP);
    
    if($OUTPUT != -1 and $EDGCSEYE ne "NULL" and $EDGCSVERB ne "NULL" and $EDGCSMOTOR ne "NULL" and $EDGCSTOTAL ne "NULL")
    {
        if($DCODE eq "REMOVEPATIENT" or $ECODE_ROW eq "REMOVEPATIENT" or $ECODE_COL eq "REMOVEPATIENT" or $AISSCORE eq "REMOVEPATIENT")
        {
            $hINC_KEY{$INC_KEY} = -1;
        }

        my $flagRemovePatient = 0;
        if(exists $hINC_KEY{$INC_KEY})
        {
            if($hINC_KEY{$INC_KEY} == -1)
            {
                $flagRemovePatient = 1;
            }
        }
        if($flagRemovePatient == 0)
        {
            # Start filling hashes
            $hOUTPUT{$INC_KEY} = $OUTPUT;
            $hINC_KEY{$INC_KEY} = 1;                            # key = INC_KEY, value = 1

            $hINC_KEY_AISCODE{$INC_KEY}{$AISCODE} = 1;          # key1 = INC_KEY, key2 = AISCODE, value = 1
            $hINC_KEY_AISSCORE{$INC_KEY}{$AISSCORE} = 1;        # key1 = INC_KEY, key2 = AISSCORE, value = 1
            $hINC_KEY_BODYREGION{$INC_KEY}{$BODYREGION} = 1;
            
            $hAGE{$INC_KEY} = $AGE;                             # key = INC_KEY, value = age of the person
            if($GENDER eq "Male" or $GENDER eq "male" or $GENDER eq "MALE")
            {
                $hGENDER{$INC_KEY} = 1;                         # key = INC_KEY, value = gender of the person
            }
            else
            {
                $hGENDER{$INC_KEY} = 0;
            }
            $hINC_KEY_DCODE{$INC_KEY}{$DCODE} = 1;              # key1 = INC_KEY, key2 = DCODE, value = 1
            $hLOS{$INC_KEY} = $LOS;                             # key = INC_KEY, value = length of stay
            $hINC_KEY_ECODE{$INC_KEY}{$ECODE} = 1;
            $hINC_KEY_ECODE_ROW{$INC_KEY}{$ECODE_ROW} = 1;
            $hINC_KEY_ECODE_COL{$INC_KEY}{$ECODE_COL} = 1;
            $hEDSYSBP{$INC_KEY} = $EDSYSBP;                     # key = INC_KEY, value = systolic blood pressure in ED
            $hEDRESPRATE{$INC_KEY} = $EDRESPRATE;               # key = INC_KEY, value = respiratory rate in ED
            $hINC_KEY_EDGCSEYE{$INC_KEY}{$EDGCSEYE} = 1;
            $hINC_KEY_EDGCSVERB{$INC_KEY}{$EDGCSVERB} = 1;
            $hINC_KEY_EDGCSMOTOR{$INC_KEY}{$EDGCSMOTOR} = 1;
            $hINC_KEY_EDGCSTOTAL{$INC_KEY}{$EDGCSTOTAL} = 1;
            $hINC_KEY_INJURYTYPE{$INC_KEY}{$INJURYTYPE} = 1;
            $hINC_KEY_INJURYSITE{$INC_KEY}{$INJURYSITE} = 1;
            
            #$EDGCSEYE_DUMMY =  ConvertUsingDummyVariables($EDGCSEYE,4);         #[1-4]
            #$EDGCSVERB_DUMMY =  ConvertUsingDummyVariables($EDGCSVERB,5);       #[1-5]     
            #$EDGCSMOTOR_DUMMY =  ConvertUsingDummyVariables($EDGCSMOTOR,6);     #[1-6]
            #$EDGCSTOTAL_DUMMY =  ConvertUsingDummyVariables($EDGCSTOTAL-2,13);  #[3-15]
            
            #print LOG "$OUTPUT: $INC_KEY, $AISCODE, $AISSCORE, $BODYREGION, $AGE, $GENDER, $DCODE, $LOS, $DISCHDISP, $DISSTATUS, $ECODE, $EDSYSBP, $EDRESPRATE, $EDGCSEYE, $EDGCSVERB, $EDGCSMOTOR, $EDGCSTOTAL, $EDDISP, $INJURYTYPE, $INJURYSITE\n";
        }
    }
    print LOG "Processing row $iter...$INC_KEY\n";    
}
my $runTime = time() - $startTime;
print LOG "Processed $iter rows of SQL data.\n";
print LOG "Time taken = $runTime seconds.\n\n";

foreach my $key (sort keys(%hINC_KEY))
{
    if($hINC_KEY{$key} == -1) # if REMOVEPATIENT
    {
       delete($hINC_KEY{$key});
       delete($hAGE{$key});
       delete($hGENDER{$key});
       delete($hLOS{$key});
       delete($hEDSYSBP{$key});
       delete($hEDRESPRATE{$key});
       delete($hOUTPUT{$key});
       
       delete($hINC_KEY_AISCODE{$key});
       delete($hINC_KEY_AISSCORE{$key});
       delete($hINC_KEY_BODYREGION{$key});
       delete($hINC_KEY_DCODE{$key});
       delete($hINC_KEY_ECODE{$key});
       delete($hINC_KEY_ECODE_ROW{$key});
       delete($hINC_KEY_ECODE_COL{$key});
       delete($hINC_KEY_EDGCSEYE{$key});
       delete($hINC_KEY_EDGCSVERB{$key});
       delete($hINC_KEY_EDGCSMOTOR{$key});
       delete($hINC_KEY_EDGCSTOTAL{$key});
       delete($hINC_KEY_INJURYTYPE{$key});
       delete($hINC_KEY_INJURYSITE{$key});
       delete($hDCODE_DCODE{$key});
       delete($hDCODE_INJURYTYPE{$key});
       delete($hAISCODE_AISCODE{$key});
       delete($hAISCODE_INJURYTYPE{$key});
       delete($hAISSCORE_BODYREGION{$key});
    }
    else
    {
        foreach my $i (sort keys %{$hINC_KEY_DCODE{$key}})
        {
            $hDCODE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_AISCODE{$key}})
        {
            $hAISCODE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_AISSCORE{$key}})
        {
            $hAISSCORE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_BODYREGION{$key}})
        {
            $hBODYREGION{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_ECODE{$key}})
        {
            $hECODE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_ECODE_ROW{$key}})
        {
            $hECODE_ROW{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_ECODE_COL{$key}})
        {
            $hECODE_COL{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_EDGCSEYE{$key}})
        {
            $hEDGCSEYE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_EDGCSVERB{$key}})
        {
            $hEDGCSVERB{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_EDGCSMOTOR{$key}})
        {
            $hEDGCSMOTOR{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_EDGCSTOTAL{$key}})
        {
            $hEDGCSTOTAL{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_INJURYTYPE{$key}})
        {
            $hINJURYTYPE{$i} = 1;
        }
        foreach my $i (sort keys %{$hINC_KEY_INJURYSITE{$key}})
        {
            $hINJURYSITE{$i} = 1;
        }
    }
}
print LOG "Number of INC_KEY keys:\nhOUTPUT = " . (keys %hOUTPUT) . "\nhINC_KEY = " . (keys %hINC_KEY) . "\nhINC_KEY_AISCODE = " . (keys %hINC_KEY_AISCODE) . "\nhINC_KEY_AISSCORE = " . (keys %hINC_KEY_AISSCORE) . "\nhINC_KEY_BODYREGION = " . (keys %hINC_KEY_BODYREGION) . "\nhAGE = " . (keys %hAGE) . "\nhGENDER = " . (keys %hGENDER) . "\nhINC_KEY_DCODE = " . (keys %hINC_KEY_DCODE) . "\nhLOS = " . (keys %hLOS) . "\nhINC_KEY_ECODE = " . (keys %hINC_KEY_ECODE) . "\nhINC_KEY_ECODE_ROW = " . (keys %hINC_KEY_ECODE_ROW) . "\nhINC_KEY_ECODE_COL = " . (keys %hINC_KEY_ECODE_COL) . "\nhEDSYSBP = " . (keys %hEDSYSBP) . "\nhEDRESPRATE = " . (keys %hEDRESPRATE) . "\nhINC_KEY_EDGCSEYE = " . (keys %hINC_KEY_EDGCSEYE) . "\nhINC_KEY_EDGCSVERB = " . (keys %hINC_KEY_EDGCSVERB) . "\nhINC_KEY_EDGCSMOTOR = " . (keys %hINC_KEY_EDGCSMOTOR) . "\nhINC_KEY_EDGCSTOTAL = " . (keys %hINC_KEY_EDGCSTOTAL) . "\nhINC_KEY_INJURYTYPE = " . (keys %hINC_KEY_INJURYTYPE) . "\nhINC_KEY_INJURYSITE = " . (keys %hINC_KEY_INJURYSITE) . "\n\n";

# Note: 1=age, 2=gender, 3=sysbp, 4=resprate
print KEYINFO "seq=0: Intercept\n";
print KEYINFO "seq=1: Age\n";
print KEYINFO "seq=2: Gender\n";
print KEYINFO "seq=3: Systolic BP\n";
print KEYINFO "seq=4: Resp Rate\n\n";

# assign sequence number for ICD9 codes.
my $seqNum = 5;		
foreach my $i (sort keys %hDCODE)
{
    $hDCODE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "ICD9 Code Keys... ". (keys %hDCODE) ." keys\n";
foreach my $i (sort keys %hDCODE)
{
    print KEYINFO "seq=$hDCODE{$i}: ICD9=$i\n";
}
print KEYINFO "\n";

# assign sequence number for AISCODE
foreach my $i (sort keys %hAISCODE)
{
    $hAISCODE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "AISCODE Keys... ". (keys %hAISCODE) ." keys\n";
foreach my $i (sort keys %hAISCODE)
{
    print KEYINFO "seq=$hAISCODE{$i}: AISCODE=$i\n";
}
print KEYINFO "\n";

## assign sequence number for AISSCORE 
#foreach my $i (sort keys %hAISSCORE)
#{
#    $hAISSCORE{$i}=$seqNum;
#    $seqNum++;        
#}
#print KEYINFO "AISSCORE Keys... ". (keys %hAISSCORE) ." keys\n";
#foreach my $i (sort keys %hAISSCORE)
#{
#    print KEYINFO "seq=$hAISSCORE{$i}, AISSCORE=$i\n";
#}
#print KEYINFO "\n";
#
## assign sequence number for BODYREGION
#foreach my $i (sort keys %hBODYREGION)
#{
#    $hBODYREGION{$i}=$seqNum;
#    $seqNum++;        
#}
#print KEYINFO "BODYREGION Keys... ". (keys %hBODYREGION) ." keys\n";
#foreach my $i (sort keys %hBODYREGION)
#{
#    print KEYINFO "seq=$hBODYREGION{$i}, BODYREGION=$i\n";
#}
#print KEYINFO "\n";

# assign sequence number for ECODE
foreach my $i (sort keys %hECODE)
{
    $hECODE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "ECODE Keys... ". (keys %hECODE) ." keys\n";
foreach my $i (sort keys %hECODE)
{
    print KEYINFO "seq=$hECODE{$i}: ECODE=$i\n";
}
print KEYINFO "\n";

# assign sequence number for ECODE_ROW
foreach my $i (sort keys %hECODE_ROW)
{
    $hECODE_ROW{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "ECODE_ROW Keys... ". (keys %hECODE_ROW) ." keys\n";
foreach my $i (sort keys %hECODE_ROW)
{
    print KEYINFO "seq=$hECODE_ROW{$i}: ECODE_ROW=$i\n";
}
print KEYINFO "\n";

# assign sequence number for ECODE_COL
foreach my $i (sort keys %hECODE_COL)
{
    $hECODE_COL{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "ECODE_COL Keys... ". (keys %hECODE_COL) ." keys\n";
foreach my $i (sort keys %hECODE_COL)
{
    print KEYINFO "seq=$hECODE_COL{$i}: ECODE_COL=$i\n";
}
print KEYINFO "\n";


# assign sequence number for EDGCSEYE
foreach my $i (sort keys %hEDGCSEYE)
{
    $hEDGCSEYE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "EDGCSEYE Keys... ". (keys %hEDGCSEYE) ." keys\n";
foreach my $i (sort keys %hEDGCSEYE)
{
    print KEYINFO "seq=$hEDGCSEYE{$i}: EDGCSEYE=$i\n";
}
print KEYINFO "\n";

# assign sequence number for EDGCSVERB
foreach my $i (sort keys %hEDGCSVERB)
{
    $hEDGCSVERB{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "EDGCSVERB Keys... ". (keys %hEDGCSVERB) ." keys\n";
foreach my $i (sort keys %hEDGCSVERB)
{
    print KEYINFO "seq=$hEDGCSVERB{$i}: EDGCSVERB=$i\n";
}
print KEYINFO "\n";

# assign sequence number for EDGCSMOTOR
foreach my $i (sort keys %hEDGCSMOTOR)
{
    $hEDGCSMOTOR{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "EDGCSMOTOR Keys...". (keys %hEDGCSMOTOR) ." keys\n";
foreach my $i (sort keys %hEDGCSMOTOR)
{
    print KEYINFO "seq=$hEDGCSMOTOR{$i}: EDGCSMOTOR=$i\n";
}
print KEYINFO "\n";

# assign sequence number for EDGCSTOTAL
foreach my $i (sort keys %hEDGCSTOTAL)
{
    $hEDGCSTOTAL{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "EDGCSTOTAL Keys...". (keys %hEDGCSTOTAL) ." keys\n";
foreach my $i (sort keys %hEDGCSTOTAL)
{
    print KEYINFO "seq=$hEDGCSTOTAL{$i}: EDGCSTOTAL=$i\n";
}
print KEYINFO "\n";

# assign sequence number for INJURYTYPE
foreach my $i (sort keys %hINJURYTYPE)
{
    $hINJURYTYPE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "INJURYTYPE Keys... ". (keys %hINJURYTYPE) ." keys\n";
foreach my $i (sort keys %hINJURYTYPE)
{
    print KEYINFO "seq=$hINJURYTYPE{$i}: INJURYTYPE=$i\n";
}
print KEYINFO "\n";

# assign sequence number for INJURYSITE
foreach my $i (sort keys %hINJURYSITE)
{
    $hINJURYSITE{$i}=$seqNum;
    $seqNum++;
}
print KEYINFO "INJURYSITE Keys... ". (keys %hINJURYSITE) ." keys\n";
foreach my $i (sort keys %hINJURYSITE)
{
    print KEYINFO "seq=$hINJURYSITE{$i}: INJURYSITE=$i\n";
}
print KEYINFO "\n";

# assign sequence number for ICD9-ICD9 two-way interactions
#my $count = 0;
# the slow method (obtained from Jerry Cheng)
#my %hTMP = %hDCODE;
#foreach my $code1(sort keys %hDCODE)
#{
#    delete($hTMP{$code1});		# to avoid [code1,code1] combinations
#    foreach my $code2(sort keys %hTMP)
#    {
#	if(&exist2Codes(\%hINC_KEY_DCODE, $code1,\%hINC_KEY_DCODE, $code2) == 1)
#        {
#            $count++;
#            print LOG "Processing two-way [ICD9,ICD9] interactions...$count\n";
#            $hDCODE_DCODE{$code1}{$code2}=$seqNum;
#            $seqNum++;
#        }
#    }        
#}

#my faster implementation
my $count = 0;
my %hTMP;

$startTime = time();
foreach my $key (sort keys %hINC_KEY_DCODE)
{
    %hTMP = %{$hINC_KEY_DCODE{$key}};
    foreach my $code1 (sort keys %hTMP)
    {
        delete($hTMP{$code1});  # to avoid [code1,code1] combinations
        foreach my $code2 (sort keys %hTMP)
        {
            if(!exists($hDCODE_DCODE{$code1}{$code2}))
            {
                $count++;
                print LOG "Processing two-way [ICD9,ICD9] interactions...$count\n";
                $hDCODE_DCODE{$code1}{$code2} = 1;
            }
        }
    }
}
foreach my $code1 (sort keys %hDCODE_DCODE)
{
    foreach my $code2 (sort keys %{$hDCODE_DCODE{$code1}})
    {
        $hDCODE_DCODE{$code1}{$code2} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [ICD9,ICD9] Keys... $count keys\n";
foreach my $i (sort keys %hDCODE_DCODE)
{
    foreach my $j (sort keys %{$hDCODE_DCODE{$i}})
    {
        print KEYINFO "seq=$hDCODE_DCODE{$i}{$j}: [ICD9,ICD9]=$i, $j\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $count two-way [ICD9,ICD9] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";

# assign sequence number for [ICD9,INJURYTYPE] two-way interactions
$count = 0;
$startTime = time();
foreach my $key (sort keys %hINC_KEY_DCODE)
{
    foreach my $code (sort keys %{$hINC_KEY_DCODE{$key}})
    {
        foreach my $injuryType (sort keys %{$hINC_KEY_INJURYTYPE{$key}})
        {
            if(!exists($hDCODE_INJURYTYPE{$code}{$injuryType}))
            {
                $count++;
                print LOG "Processing two-way [ICD9,INJURYTYPE] interactions...$count\n";
                $hDCODE_INJURYTYPE{$code}{$injuryType} = 1;
            }
        }
    }
}
foreach my $code (sort keys %hDCODE_INJURYTYPE)
{
    foreach my $injuryType (sort keys %{$hDCODE_INJURYTYPE{$code}})
    {
        $hDCODE_INJURYTYPE{$code}{$injuryType} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [ICD9,INJURYTYPE] Keys... $count keys\n";
foreach my $code (sort keys %hDCODE_INJURYTYPE)
{
    foreach my $injuryType (sort keys %{$hDCODE_INJURYTYPE{$code}})
    {
        print KEYINFO "seq=$hDCODE_INJURYTYPE{$code}{$injuryType}: [ICD9,INJURYTYPE]=$code, $injuryType\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $count two-way [ICD9,INJURYTYPE] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";

# assign sequence number for [AISCODE,AISCODE] two-way interactions
$count = 0;
$startTime = time();
foreach my $key (sort keys %hINC_KEY_AISCODE)
{
    %hTMP = %{$hINC_KEY_AISCODE{$key}};
    foreach my $code1 (sort keys %hTMP)
    {
        delete($hTMP{$code1});  # to avoid [code1,code1] combinations
        foreach my $code2 (sort keys %hTMP)
        {
            if(!exists($hAISCODE_AISCODE{$code1}{$code2}))
            {
                $count++;
                print LOG "Processing two-way [AISCODE,AISCODE] interactions...$count\n";
                $hAISCODE_AISCODE{$code1}{$code2} = 1;
            }
        }
    }
}
foreach my $code1 (sort keys %hAISCODE_AISCODE)
{
    foreach my $code2 (sort keys %{$hAISCODE_AISCODE{$code1}})
    {
        $hAISCODE_AISCODE{$code1}{$code2} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [AISCODE,AISCODE] Keys... $count keys\n";
foreach my $code1 (sort keys %hAISCODE_AISCODE)
{
    foreach my $code2 (sort keys %{$hAISCODE_AISCODE{$code1}})
    {
        print KEYINFO "seq=$hAISCODE_AISCODE{$code1}{$code2}: [AISCODE,AISCODE]=$code1, $code2\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $count two-way [AISCODE,AISCODE] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";

# assign sequence number for [AISCODE,INJURYTYPE] two-way interactions
$count = 0;
$startTime = time();
foreach my $key (sort keys %hINC_KEY_AISCODE)
{
    foreach my $code (sort keys %{$hINC_KEY_AISCODE{$key}})
    {
        foreach my $injuryType (sort keys %{$hINC_KEY_INJURYTYPE{$key}})
        {
            if(!exists($hAISCODE_INJURYTYPE{$code}{$injuryType}))
            {
                $count++;
                print LOG "Processing two-way [AISCODE,INJURYTYPE] interactions...$count\n";
                $hAISCODE_INJURYTYPE{$code}{$injuryType} = 1;
            }
        }
    }
}
foreach my $code (sort keys %hAISCODE_INJURYTYPE)
{
    foreach my $injuryType (sort keys %{$hAISCODE_INJURYTYPE{$code}})
    {
        $hAISCODE_INJURYTYPE{$code}{$injuryType} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [AISCODE,INJURYTYPE] Keys... $count keys\n";
foreach my $code (sort keys %hAISCODE_INJURYTYPE)
{
    foreach my $injuryType (sort keys %{$hAISCODE_INJURYTYPE{$code}})
    {
        print KEYINFO "seq=$hAISCODE_INJURYTYPE{$code}{$injuryType}: [AISCODE,INJURYTYPE]=$code, $injuryType\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $count two-way [AISCODE,INJURYTYPE] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";

# assign sequence number for [AISSCORE,BODYREGION] two-way interactions
$count = 0;
$startTime = time();
foreach my $key (sort keys %hINC_KEY_AISSCORE)
{
    foreach my $score (sort keys %{$hINC_KEY_AISSCORE{$key}})
    {
        foreach my $bodyRegion (sort keys %{$hINC_KEY_BODYREGION{$key}})
        {
            if(!exists($hAISSCORE_BODYREGION{$score}{$bodyRegion}))
            {
                $count++;
                print LOG "Processing two-way [AISSCORE,BODYREGION] interactions...$count\n";
                $hAISSCORE_BODYREGION{$score}{$bodyRegion} = 1;
            }
        }
    }
}
foreach my $score (sort keys %hAISSCORE_BODYREGION)
{
    foreach my $bodyRegion (sort keys %{$hAISSCORE_BODYREGION{$score}})
    {
        $hAISSCORE_BODYREGION{$score}{$bodyRegion} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [AISSCORE,BODYREGION] Keys... $count keys\n";
foreach my $score (sort keys %hAISSCORE_BODYREGION)
{
    foreach my $bodyRegion (sort keys %{$hAISSCORE_BODYREGION{$score}})
    {
        print KEYINFO "seq=$hAISSCORE_BODYREGION{$score}{$bodyRegion}: [AISSCORE,BODYREGION]=$score, $bodyRegion\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $count two-way [AISSCORE,BODYREGION] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";

# Construct array of valid INC_KEYs
my @inc_key_valid;
foreach my $key (sort keys(%hINC_KEY))
{
    if($hINC_KEY{$key} == 1)
    {
       push(@inc_key_valid,$key);
    }
}
my $nPatients = $#inc_key_valid + 1;

foreach my $key (@inc_key_valid)
{
    print EDSYSBP "$key, $hAGE{$key}, $hEDSYSBP{$key}, $hOUTPUT{$key}, $hLOS{$key}\n";
}

foreach my $key (@inc_key_valid)
{
    print EDRESPRATE "$key, $hAGE{$key}, $hEDRESPRATE{$key}, $hOUTPUT{$key}, $hLOS{$key}\n";
}

# start to print out data 
foreach my $key (@inc_key_valid)
{
    my $index=0;

    if (length($hLOS{$key})==0) {
            print KEYINFO "watch out for $key ...\n";
    }

    print OUTHD "$hLOS{$key}" . ":" . "$hOUTPUT{$key} ";
    print OUTLD "$hLOS{$key}" . ":" . "$hOUTPUT{$key} ";
#    print OUTHD "$index:1 ";				# intercept term should not be printed, since it is explicitly added in C++ code

    $index++;
    print OUTHD "$index:$hAGE{$key} ";
    print OUTLD "$index:$hAGE{$key} ";

    $index++;
    print OUTHD "$index:$hGENDER{$key} ";
    print OUTLD "$index:$hGENDER{$key} ";
    
    $index++;
    print OUTHD "$index:$hEDSYSBP{$key} ";
    print OUTLD "$index:$hEDSYSBP{$key} ";
    
    $index++;
    print OUTHD "$index:$hEDRESPRATE{$key} ";
    print OUTLD "$index:$hEDRESPRATE{$key} ";

    # ICD9 
    foreach my $j (sort keys %{$hINC_KEY_DCODE{$key}})
    {
        print OUTHD $hDCODE{$j} . ":1 ";
    }
	
    #AISCODE
    foreach my $j (sort keys %{$hINC_KEY_AISCODE{$key}})
    {
        print OUTHD $hAISCODE{$j} . ":1 ";
    }
    
    ##AISSCORE
    #foreach my $j (sort keys %{$hINC_KEY_AISSCORE{$key}})
    #{
    #    print OUTHD $hAISSCORE{$j} . ":1 ";
    #}
    #
    ##BODYREGION
    #foreach my $j (sort keys %{$hINC_KEY_BODYREGION{$key}})
    #{
    #    print OUTHD $hBODYREGION{$j} . ":1 ";
    #}
    
    #ECODE
    foreach my $j (sort keys %{$hINC_KEY_ECODE{$key}})
    {
        print OUTHD $hECODE{$j} . ":1 ";
    }
    
    #ECODE_ROW
    foreach my $j (sort keys %{$hINC_KEY_ECODE_ROW{$key}})
    {
        print OUTHD $hECODE_ROW{$j} . ":1 ";
    }
    
    #ECODE_COL
    foreach my $j (sort keys %{$hINC_KEY_ECODE_COL{$key}})
    {
        print OUTHD $hECODE_COL{$j} . ":1 ";
    }
    
    #EDGCSEYE
    foreach my $j (sort keys %{$hINC_KEY_EDGCSEYE{$key}})
    {
        print OUTHD $hEDGCSEYE{$j} . ":1 ";
    }
    
    #EDGCSVERB
    foreach my $j (sort keys %{$hINC_KEY_EDGCSVERB{$key}})
    {
        print OUTHD $hEDGCSVERB{$j} . ":1 ";
    }
    
    #EDGCSMOTOR
    foreach my $j (sort keys %{$hINC_KEY_EDGCSMOTOR{$key}})
    {
        print OUTHD $hEDGCSMOTOR{$j} . ":1 ";
    }
    
    #EDGCSTOTAL
    foreach my $j (sort keys %{$hINC_KEY_EDGCSTOTAL{$key}})
    {
        print OUTHD $hEDGCSTOTAL{$j} . ":1 ";
        print OUTLD $hEDGCSTOTAL{$j} . ":1 ";
    }
    
    #INJURYTYPE
    foreach my $j (sort keys %{$hINC_KEY_INJURYTYPE{$key}})
    {
        print OUTHD $hINJURYTYPE{$j} . ":1 ";
        print OUTLD $hINJURYTYPE{$j} . ":1 ";
    }
    
    #INJURYSITE
    foreach my $j (sort keys %{$hINC_KEY_INJURYSITE{$key}})
    {
        print OUTHD $hINJURYSITE{$j} . ":1 ";
    }
    
    # Two-way [ICD9,ICD9] codes
    %hTMP = %{$hINC_KEY_DCODE{$key}};
    foreach my $code1(sort keys %{$hINC_KEY_DCODE{$key}})
    {
        delete($hTMP{$code1});		# to avoid [code1,code1] combinations
        foreach my $code2(sort keys %hTMP)
        {
            print OUTHD $hDCODE_DCODE{$code1}{$code2} . ":1 ";
        }
    }

    # Two-way [ICD9,INJURYTYPE] codes
    foreach my $code(sort keys %{$hINC_KEY_DCODE{$key}})
    {
        foreach my $injuryType(sort keys %{$hINC_KEY_INJURYTYPE{$key}})
        {
            print OUTHD $hDCODE_INJURYTYPE{$code}{$injuryType} . ":1 ";
        }
    }
    
    # Two-way [AISCODE,AISCODE] codes
    %hTMP = %{$hINC_KEY_AISCODE{$key}};
    foreach my $code1(sort keys %{$hINC_KEY_AISCODE{$key}})
    {
        delete($hTMP{$code1});		# to avoid [code1,code1] combinations
        foreach my $code2(sort keys %hTMP)
        {
            print OUTHD $hAISCODE_AISCODE{$code1}{$code2} . ":1 ";
        }
    }
    
    # Two-way [AISCODE,INJURYTYPE] codes
    foreach my $code(sort keys %{$hINC_KEY_AISCODE{$key}})
    {
        foreach my $injuryType(sort keys %{$hINC_KEY_INJURYTYPE{$key}})
        {
            print OUTHD $hAISCODE_INJURYTYPE{$code}{$injuryType} . ":1 ";
        }
    }
    
    # Two-way [AISSCORE,BODYREGION] codes
    foreach my $score(sort keys %{$hINC_KEY_AISSCORE{$key}})
    {
        foreach my $bodyRegion(sort keys %{$hINC_KEY_BODYREGION{$key}})
        {
            print OUTHD $hAISSCORE_BODYREGION{$score}{$bodyRegion} . ":1 ";
        }
    }    
    
    print OUTHD "\n";
    print OUTLD "\n";
}

print LOG "Processed $iter lines. Total number of rows = $iter, Total Patients = $nPatients\n";

$ntdb->disconnect();
close(KEYINFO);
close(LOG);
close(OUTHD);
close(OUTLD);
close(EDSYSBP);
close(EDRESPRATE);